#!/usr/bin/env bash
# mingw-w64-build - download and build mingw-w64 toolchain
#
# Copyright 2021 XiongJing
# Released under the MIT License. See LICENSE for details.
# https://gitee.com/vip666mylife999/mingw-w64-build-for-win

#The best base url for me.You can run "Find_best_base_url" to find the best base url and change best_base_url to it. 
best_base_url="https://mirrors.aliyun.com/gnu/"

# checks for required external tools
function check_dependencies {  # check_dependencies $DEP1 $DEP2 ...
    local DEPS DEPS_EACH DEPS_MULTI ERRORS FOUND
    DEPS=("${@}");
    ERRORS=()
    for DEPS_EACH in ${DEPS[@]}; do
        DEPS_MULTI=(${DEPS_EACH//|/ })
        FOUND=false
        for DEP in ${DEPS_MULTI[@]}; do
            if echo "${DEP}" | grep '/' >/dev/null 2>&1 && [[ -x "${DEP}" ]]; then
                FOUND=true
                break
            elif hash "${DEP}" >/dev/null 2>&1; then
                FOUND=true
                break
            fi
        done
        if [[ "${FOUND}" == false ]]; then
            ERRORS+=("$(echo ${DEPS_MULTI[@]} | sed 's/ /|/')")
        fi
    done
    if [[ "${#ERRORS[@]}" -ne 0 ]]; then
        echo "dependencies: ${DEPS[@]}"
        echo "unable to find command(s): ${ERRORS[*]}" >&2
        return 1
    fi
}

# downloads from one or more urls
function download_url {  # download_url $VERBOSE $FILE $URLS
    local VERBOSE FILE URLS I FAILED
    OPTIND=1
    VERBOSE="${1}"
    FILE="${2}"
    shift 2
    URLS=("${@}")
    if [[ "${#URLS[@]}" -eq 0 ]] || [[ "${URLS[0]:-}" == "" ]]; then
        echo "url not specified for download" >&2
        return 1
    fi
    if [[ "${FILE:-}" == "" ]]; then
        echo "output path not specified for download: ${FILE}" >&2
        return 1
    fi
    FAILED=()
    for I in "${!URLS[@]}"; do
        if ! touch "${FILE}" >/dev/null 2>&1; then
            echo "unable to create path: ${FILE}" >&2
            return 1
        fi
        if [[ "${VERBOSE:-}" == true ]]; then
            echo "curl -Lf --connect-timeout 30 \"${URLS[I]}\" -o \"${FILE}\""
        fi
        if ! curl -Lf --connect-timeout 30 "${URLS[I]}" -o "${FILE}" >/dev/null 2>&1; then
            FAILED+=("${URLS[I]}")
            if [[ "$(( ${I} + 1 ))" -lt "${#URLS[@]}" ]]; then
                continue
            else
                echo "unable to download from urls: ${FAILED[@]}" >&2
                echo "unable to download to file: ${FILE}" >&2
                return 1
            fi
        fi
        return 0
    done
}

# prints continuous output to avoid timeouts on build systems like Travis
function display_progress {
    local str=""
    while [ "$(ps a | awk '{print $1}' | grep ${1})" ]; do
        printf "%c" "$str"
        sleep 5
        str="."
    done
}

# kills child processes
function die_gracefully {   
    trap - EXIT INT
    trap ":" INT  # prevent recursion due to spamming ctrl-c
    echo ""
    trap - TERM && kill -- -$$
}

# tests whether a string is an exact match for an array item
function in_array {  # in_array needle haystack[@]
    local e
    for e in "${@:2}"; do
        [[ "${e}" == "${1}" ]] && return 0
    done
    return 1
}

# builds mingw-w64
function mingw-w64-build {  # mingw-w64-build [args] $TARGET_PARAM $TARGET_DIR
    set -o pipefail

    # package names
    local CONFIG_NAME BINUTILS_NAME MINGW_W64_NAME GMP_NAME MPFR_NAME MPC_NAME ISL_NAME GCC_NAME GDB_NAME MAKE_NAME NASM_NAME EXPAT_NAME NAMES
    CONFIG_NAME="config"
    BINUTILS_NAME="binutils"
    MINGW_W64_NAME="mingw-w64"
    GMP_NAME="gmp"
    MPFR_NAME="mpfr"
    MPC_NAME="mpc"
    ISL_NAME="isl"
    GCC_NAME="gcc"
    MAKE_NAME="make"
    NASM_NAME="nasm"
    EXPAT_NAME="expat"
    NAMES=("${CONFIG_NAME}" "${BINUTILS_NAME}" "${MINGW_W64_NAME}" "${GMP_NAME}" "${MPFR_NAME}" "${MPC_NAME}" "${ISL_NAME}" "${GCC_NAME}" "${MAKE_NAME}" "${NASM_NAME}" "${EXPAT_NAME}")

    # versions
    local CONFIG_VER BINUTILS_VER MINGW_W64_VER GMP_VER MPFR_VER MPC_VER ISL_VER GCC_VER GDB_VER MAKE_VER NASM_VER EXPAT_VER VERSIONS
    CONFIG_VER="77632d9"  # config.guess 2020-11-07
    BINUTILS_VER="2.35.1"
    MINGW_W64_VER="8.0.0"
    GMP_VER="6.2.0"
    MPFR_VER="4.1.0"
    MPC_VER="1.2.1"
    ISL_VER="0.22.1"
    GCC_VER="10.2.0"
    MAKE_VER="4.2.1"
    NASM_VER="2.15.05"
    EXPAT_VER="2.2.9"
    VERSIONS=("${CONFIG_VER}" "${BINUTILS_VER}" "${MINGW_W64_VER}" "${GMP_VER}" "${MPFR_VER}" "${MPC_VER}" "${ISL_VER}" "${GCC_VER}" "${MAKE_VER}" "${NASM_VER}" "${EXPAT_VER}")

    # filenames
    local CONFIG_PKG BINUTILS_PKG MINGW_W64_PKG GMP_PKG MPFR_PKG MPC_PKG ISL_PKG GCC_PKG GDB_PKG MAKE_PKG NASM_PKG EXPAT_PKG PKGS
    CONFIG_PKG="config-${CONFIG_VER}.tar.gz"
    BINUTILS_PKG="binutils-${BINUTILS_VER}.tar.bz2"
    MINGW_W64_PKG="mingw-w64-v${MINGW_W64_VER}.tar.bz2"
    GMP_PKG="gmp-${GMP_VER}.tar.bz2"
    MPFR_PKG="mpfr-${MPFR_VER}.tar.gz"
    MPC_PKG="mpc-${MPC_VER}.tar.gz"
    ISL_PKG="isl-${ISL_VER}.tar.bz2"
    GCC_PKG="gcc-${GCC_VER}.tar.gz"
    MAKE_PKG="make-${MAKE_VER}.tar.gz"
    NASM_PKG="nasm-${NASM_VER}.tar.gz"
    EXPAT_PKG="expat-${EXPAT_VER}.tar.gz"
    PKGS=("${CONFIG_PKG}" "${BINUTILS_PKG}" "${MINGW_W64_PKG}" "${GMP_PKG}" "${MPFR_PKG}" "${MPC_PKG}" "${ISL_PKG}" "${GCC_PKG}" "${MAKE_PKG}" "${NASM_PKG}" "${EXPAT_PKG}")

    # urls
    local CONFIG_URLS BINUTILS_URLS MINGW_W64_URLS GMP_URLS MPFR_URLS MPC_URLS ISL_URLS GCC_URLS GDB_URLS URLS_VARNAMES MAKE_URLS NASM_URLS EXPAT_URLS
    CONFIG_URLS=("https://git.savannah.gnu.org/gitweb/?p=config.git;a=snapshot;h=${CONFIG_VER};sf=tgz" "${ARCHIVE_URL}/${CONFIG_PKG}")
    BINUTILS_URLS=("${best_base_url}binutils/binutils-${BINUTILS_VER}.tar.bz2" "${ARCHIVE_URL}/${BINUTILS_PKG}")
    MINGW_W64_URLS=("http://downloads.sourceforge.net/project/mingw-w64/mingw-w64/mingw-w64-release/mingw-w64-v${MINGW_W64_VER}.tar.bz2" "${ARCHIVE_URL}/${MINGW_W64_PKG}")
    GMP_URLS=("${best_base_url}gmp/gmp-${GMP_VER}.tar.bz2" "${ARCHIVE_URL}/${GMP_PKG}")
    MPFR_URLS=("${best_base_url}mpfr/mpfr-${MPFR_VER}.tar.gz" "${ARCHIVE_URL}/${MPFR_PKG}")
    MPC_URLS=("${best_base_url}mpc/mpc-${MPC_VER}.tar.gz" "${ARCHIVE_URL}/${MPC_PKG}")
    ISL_URLS=("http://isl.gforge.inria.fr/isl-${ISL_VER}.tar.bz2" "${ARCHIVE_URL}/${ISL_PKG}")
    GCC_URLS=("${best_base_url}gcc/gcc-${GCC_VER}/gcc-${GCC_VER}.tar.gz" "${ARCHIVE_URL}/${GCC_PKG}")
    MAKE_URLS=("${best_base_url}make/make-${MAKE_VER}.tar.gz" "${ARCHIVE_URL}/${MAKE_PKG}")
    NASM_URLS=("https://www.nasm.us/pub/nasm/stable/nasm-${NASM_VER}.tar.gz" "${ARCHIVE_URL}/${NASM_PKG}")
    EXPAT_URLS=("https://sourceforge.net/projects/expat/files/expat/${EXPAT_VER}/expat-${EXPAT_VER}.tar.gz" "${ARCHIVE_URL}/${EXPAT_PKG}")
    URLS_VARNAMES=('CONFIG_URLS' 'BINUTILS_URLS' 'MINGW_W64_URLS' 'GMP_URLS' 'MPFR_URLS' 'MPC_URLS' 'ISL_URLS' 'GCC_URLS' 'MAKE_URLS' 'NASM_URLS' 'EXPAT_URLS')

    # checksums
    local CONFIG_SHA256 BINUTILS_SHA256 MINGW_W64_SHA256 GMP_SHA256 MPFR_SHA256 MPC_SHA256 ISL_SHA256 GCC_SHA256 GDB_SHA256 MAKE_SHA256 EXPAT_SHA256 NASM_SHA256 CHECKSUMS
    CONFIG_SHA256="74a9d78c80258ae18e275c272056d6a7f606230c029890c614fa805ea44bb0bf"
    BINUTILS_SHA256="320e7a1d0f46fcd9f413f1046e216cbe23bb2bce6deb6c6a63304425e48b1942"
    MINGW_W64_SHA256="44c740ea6ab3924bc3aa169bad11ad3c5766c5c8459e3126d44eabb8735a5762"
    GMP_SHA256="f51c99cb114deb21a60075ffb494c1a210eb9d7cb729ed042ddb7de9534451ea"
    MPFR_SHA256="3127fe813218f3a1f0adf4e8899de23df33b4cf4b4b3831a5314f78e65ffa2d6"
    MPC_SHA256="17503d2c395dfcf106b622dc142683c1199431d095367c6aacba6eec30340459"
    ISL_SHA256="1a668ef92eb181a7c021e8531a3ca89fd71aa1b3744db56f68365ab0a224c5cd"
    GCC_SHA256="27e879dccc639cd7b0cc08ed575c1669492579529b53c9ff27b0b96265fa867d"
    MAKE_SHA256="e40b8f018c1da64edd1cc9a6fce5fa63b2e707e404e20cad91fbae337c98a5b7"
    EXPAT_SHA256="4456e0aa72ecc7e1d4b3368cd545a5eec7f9de5133a8dc37fdb1efa6174c4947"
    NASM_SHA256="9182a118244b058651c576baa9d0366ee05983c4d4ae1d9ddd3236a9f2304997"
    CHECKSUMS=("${CONFIG_SHA256}" "${BINUTILS_SHA256}" "${MINGW_W64_SHA256}" "${GMP_SHA256}" "${MPFR_SHA256}" "${MPC_SHA256}" "${ISL_SHA256}" "${GCC_SHA256}" "${MAKE_SHA256}" "${NASM_SHA256}" "${EXPAT_SHA256}")

    # internal vars
    local NAME VERSION SELF SELF_NAME HELP
    NAME="mingw-w64-build"
    VERSION="9.2.0"
    SELF="${BASH_SOURCE[0]}"
    SELF_NAME=$(basename "${SELF}")
    HELP="\
${NAME} ${VERSION}
usage: ${SELF_NAME} [-h | --help]
       ${SELF_NAME} [-l | --list]
       ${SELF_NAME} [-v | --version]
       ${SELF_NAME} [-f | --force] [-j # | --jobs #] [--disable-gdb] target [install-dir]
where:
  -h, --help
        display this help text
  -l, --list
        display components list
  -v, --version
        display version information
  -f, --force
        remove and replace existing target (overwrite)
  -j, --jobs
        number of concurrent build jobs to run
        default: 0 (automatic)
  --disable-gdb
        disable building GDB debugger
targets:
  i686
  i686.clean
  i686.distclean
  x86_64
  x86_64.clean
  x86_64.distclean
  pkgclean
default install-dir: ${HOME}/toolchains/mingw-w64-${MINGW_W64_VER}-gcc-${GCC_VER}"

    # args
    local FORCE JOBS LIST DISABLE_GDB OPTIND OPTSPEC OPTARRAY
    FORCE=false
    JOBS=0
    LIST=false
    DISABLE_GDB=false
    OPTIND=1
    OPTSPEC=":-:hlvfj:"
    OPTARRAY=('-h' '--help' '-l' '--list' '-v' '--version' '--force' '-j' '--jobs' '--disable-gdb')  # all short and long options
    while getopts "${OPTSPEC}" OPT; do
        case "${OPT}" in
            -)
                case "${OPTARG}" in
                    help)
                        # Print help and exit
                        echo -e "${HELP}"
                        return 0
                        ;;
                    help=*)
                        # Print help and exit
                        echo -e "${HELP}"
                        return 0
                        ;;
                    list)
                        # List components
                        LIST=true
                        ;;
                    list=*)
                        # List components
                        LIST=true
                        ;;
                    version)
                        # Print version and exit
                        echo -e "${NAME} ${VERSION}"
                        return 0
                        ;;
                    version=*)
                        # Print version and exit
                        echo -e "${NAME} ${VERSION}"
                        return 0
                        ;;
                    force)
                        # Force remove and replace dist (overwrite)
                        FORCE=true
                        ;;
                    force=*)
                        # Option with prohibited value
                        echo "Option --${OPTARG%%=*} takes no value" >&2
                        echo -e "${HELP}"
                        return 1
                        ;;
                    jobs)
                        # Number of jobs
                        if [[ -z ${!OPTIND+isset} ]] || in_array "${!OPTIND}" "${OPTARRAY[@]}"; then
                            # Option without required argument
                            echo "Option --${OPTARG} requires a value" >&2
                            echo -e "${HELP}"
                            return 1
                        fi
                        JOBS="${!OPTIND}"
                        if [[ ! "${JOBS}" =~ ^[0-9]*$ ]]; then
                            echo "Option --${OPTARG} requires a numeric value" >&2
                            echo -e "${HELP}"
                            return 1
                        fi
                        OPTIND=$((OPTIND + 1))
                        ;;
                    jobs=*)
                        # Number of jobs
                        JOBS="${OPTARG#*=}"
                        if [[ ! "${JOBS}" =~ ^[0-9]*$ ]]; then
                            echo "Option --${OPTARG} requires a numeric value" >&2
                            echo -e "${HELP}"
                            return 1
                        fi
                        ;;
                    disable-gdb)
                        # Disable GDB
                        DISABLE_GDB=true
                        ;;
                    *)
                        if [[ "${OPTERR}" == 1 ]]; then
                            # Invalid option specified
                            echo "Invalid option: --${OPTARG}" >&2
                            echo -e "${HELP}"
                            return 1
                        fi
                        ;;
                esac
                ;;
            h)
                # Print help and exit
                echo -e "${HELP}"
                return 0
                ;;
            l)
                # List components
                LIST=true
                ;;
            v)
                # Print version and exit
                echo "${NAME} ${VERSION}"
                return 0
                ;;
            f)
                # Force remove and replace dist (overwrite)
                FORCE=true
                ;;
            j)
                # Number of jobs
                JOBS="${OPTARG}"
                if [[ ! "${JOBS}" =~ ^[0-9]*$ ]]; then
                    echo "Option -${OPT} requires a numeric value" >&2
                    echo -e "${HELP}"
                    return 1
                fi
                ;;
            :)
                # Option without required value
                echo "Option -${OPTARG} requires a value" >&2
                echo -e "${HELP}"
                return 1
                ;;
            \?)
                # Invalid option specified
                echo "Invalid option: -${OPTARG}" >&2
                echo -e "${HELP}"
                return 1
                ;;
        esac
    done
    shift $((OPTIND - 1))

    # gdb?
    if [[ "${DISABLE_GDB}" == false ]] || [[ "${LIST}" == true ]]; then
        GDB_NAME="gdb"
        NAMES+=("${GDB_NAME}")
        GDB_VER="10.1"
        VERSIONS+=("${GDB_VER}")
        GDB_PKG="gdb-${GDB_VER}.tar.gz"
        PKGS+=("${GDB_PKG}")
        GDB_URLS=("${best_base_url}gdb/gdb-${GDB_VER}.tar.gz" "${ARCHIVE_URL}/${GDB_PKG}")
        URLS_VARNAMES+=('GDB_URLS')
        GDB_SHA256="f12f388b99e1408c01308c3f753313fafa45517740c81ab7ed0d511b13e2cf55"
        CHECKSUMS+=("${GDB_SHA256}")
    fi

    # host
    local SYS_NAME SYS_ARCH CPU_COUNT
    SYS_NAME=$(uname | awk '{ print tolower($0)}')
    SYS_ARCH=$(uname -m)
    if [[ "${SYS_NAME}" == "darwin" ]]; then
        CPU_COUNT=$(sysctl -n hw.activecpu 2>/dev/null)
    elif [[ "${SYS_NAME}" == "linux" ]]; then
        CPU_COUNT=$(grep -c processor /proc/cpuinfo 2>/dev/null)
    fi
    CPU_COUNT="${CPU_COUNT:-1}"
    [[ "${JOBS}" -eq 0 ]] && JOBS="${CPU_COUNT}"

    # begin output
    echo "${NAME} ${VERSION} (${JOBS} job$([[ ${JOBS} -gt 1 ]] && echo 's'))"

    # list components
    if [[ "${LIST}" == true ]]; then
        local COMPONENTS COMPONENTS_TEMP
        COMPONENTS_TEMP=()
        for I in "${!NAMES[@]}"; do
            COMPONENTS_TEMP+=("${NAMES[$I]} ${VERSIONS[$I]}")
        done
        COMPONENTS_TEMP+=('winpthreads')
        OIFS="${IFS}"
        IFS=$'\n'
        COMPONENTS=($(sort <<< "${COMPONENTS_TEMP[*]}"))
        IFS="${OIFS}"
        echo "Components:"
        for I in "${!COMPONENTS[@]}"; do
            echo "  ${COMPONENTS[$I]}"
        done
        return 0
    fi

    # dependencies
    local DEPS
    DEPS=("bison" "bzip2" "curl" "flex" "g++" "gcc" "gunzip" "m4" "make" "pax" "shasum|sha256sum")
    check_dependencies "${DEPS[@]}" || return 1

    # sha256 binary
    local SHA256
    if hash shasum >/dev/null 2>&1; then
        SHA256="shasum -a 256"
    elif hash sha256sum >/dev/null 2>&1; then
        SHA256="sha256sum"
    else
        return 1
    fi

    # target args
    local TARGET_PARAM TARGET_DIR TARGET_i686 TARGET_x86_64 PREFIX_i686 PREFIX_x86_64 TARGET PREFIX
    TARGET_PARAM="${1}"
    TARGET_DIR="${2}"
    TARGET_i686="i686-w64-mingw32"
    TARGET_x86_64="x86_64-w64-mingw32"
    PREFIX_i686="mingw-w64-i686"
    PREFIX_x86_64="mingw-w64-x86_64"
    if [[ "${TARGET_PARAM:-}" == "" ]]; then
        echo -e "${HELP}"
        echo "no target specified" >&2
        return 1
    fi
    case "${TARGET_PARAM}" in
        i686|i686.clean|i686.distclean)
            TARGET="${TARGET_i686}"
            PREFIX="${PREFIX_i686}"
            ;;
        x86_64|x86_64.clean|x86_64.distclean)
            TARGET="${TARGET_x86_64}"
            PREFIX="${PREFIX_x86_64}"
            ;;
        pkgclean)
            TARGET="pkgclean"
            PREFIX="pkgclean"
            ;;
    esac
    if [[ "${PREFIX:-}" == "" ]]; then
        echo -e "${HELP}"
        echo "target not valid: ${TARGET_PARAM}" >&2
        return 1
    fi
    if [[ "${TARGET_DIR:-}" == "" ]]; then
        TARGET_DIR="${HOME}/toolchains/mingw-w64-${MINGW_W64_VER}-gcc-${GCC_VER}"
    fi

    # create target directory
    mkdir -p "${TARGET_DIR}"
    if [[ ! -d "${TARGET_DIR}" ]]; then
        echo "unable to create directory: ${TARGET_DIR}" >&2
        return 1
    fi

    # directories
    local BASE_DIR MINGW_W64_DIR PKG_DIR SOURCE_DIR BUILD_DIR LOG_DIR
    BASE_DIR=$(pwd)
    cd "${TARGET_DIR}"
    TARGET_DIR=$(pwd)
    cd "${BASE_DIR}"
    MINGW_W64_DIR="${TARGET_DIR}/${PREFIX}"
    MINGW_W64_DIR_FOR_WIN="${TARGET_DIR}/${PREFIX}-for-win"
    PKG_DIR="${TARGET_DIR}/pkg"
    SOURCE_DIR="${TARGET_DIR}/source.noindex"
    BUILD_DIR="${TARGET_DIR}/build-${PREFIX}.noindex"
    BUILD_DIR_FOR_WIN="${TARGET_DIR}/build-${PREFIX}.noindex-for-win"
    LOG_DIR="${BUILD_DIR}"
    LOG_DIR_FOR_WIN="${BUILD_DIR_FOR_WIN}"

    # clean
    case "${TARGET_PARAM}" in
        i686.clean|x86_64.clean)
            echo "rm -rf \"${BUILD_DIR}\" "
            echo "rm -rf \"${SOURCE_DIR}\" "
            rm -rf "${BUILD_DIR}"
            rm -rf "${SOURCE_DIR}"
            return 0
            ;;
        i686.distclean|x86_64.distclean)
            echo "rm -rf \"${MINGW_W64_DIR}\" "
            rm -rf "${MINGW_W64_DIR}"
            return 0
            ;;
        pkgclean)
            echo "rm -rf \"${PKG_DIR}\" "
            rm -rf "${PKG_DIR}"
            return 0
            ;;
    esac

    # remove non-reusable directories
    local CLEAN_INDEX CLEAN_TOTAL
    CLEAN_INDEX=0
    CLEAN_TOTAL=2
    if [[ "${FORCE}" == true ]]; then
        CLEAN_INDEX=$((CLEAN_INDEX+1))
        CLEAN_TOTAL=$((CLEAN_TOTAL+1))
        printf "Cleaning    [%02i/%02i] dist " "${CLEAN_INDEX}" "${CLEAN_TOTAL}"
        rm -rf "${MINGW_W64_DIR}"
        echo ""
    elif [[ -e "${MINGW_W64_DIR}" ]]; then
        # prefix dir should not exist
        echo "unable to create directory (exists): ${MINGW_W64_DIR}" >&2
        echo "remove with: ${SELF_NAME} ${TARGET_PARAM%%.*}.distclean${2:+ $2}" >&2
        return 1
    fi
    CLEAN_INDEX=$((CLEAN_INDEX+1))
    printf "Cleaning    [%02i/%02i] source " "${CLEAN_INDEX}" "${CLEAN_TOTAL}"
    rm -rf "${SOURCE_DIR}"
    CLEAN_INDEX=$((CLEAN_INDEX+1))
    echo ""
    printf "Cleaning    [%02i/%02i] build " "${CLEAN_INDEX}" "${CLEAN_TOTAL}"
    rm -rf "${BUILD_DIR}"
    rm -rf "${BUILD_DIR_FOR_WIN}"

    # verify/fetch
    mkdir -p "${PKG_DIR}"
    if [[ ! -d "${PKG_DIR}" ]]; then
        echo "unable to create directory: ${PKG_DIR}" >&2
        return 1
    fi
    local DOWNLOAD_VERBOSE I URLS_IREF URLS CHECKSUM
    DOWNLOAD_VERBOSE=false
    for I in "${!PKGS[@]}"; do
        echo ""
        printf "Downloading [%02i/%02i] %s " "$((I+1))" "${#PKGS[@]}" "${NAMES[I]} ${VERSIONS[I]}"
        URLS_IREF="${URLS_VARNAMES[I]}[@]"
        URLS="${!URLS_IREF}"
        CHECKSUM=$(${SHA256} "${PKG_DIR}/${PKGS[I]}" 2>/dev/null | awk '{ print $1 }')
        if [[ "${CHECKSUM}" != "${CHECKSUMS[I]}" ]] >/dev/null 2>&1; then
            download_url "${DOWNLOAD_VERBOSE}" "${PKG_DIR}/${PKGS[I]}" ${URLS[@]} || return 1
        fi
        CHECKSUM=$(${SHA256} "${PKG_DIR}/${PKGS[I]}" 2>/dev/null | awk '{ print $1 }')
        if [[ "${CHECKSUM}" != "${CHECKSUMS[I]}" ]]; then
            echo "checksum mismatch for package: ${PKG_DIR}/${PKGS[I]}" >&2
            echo "expected: ${CHECKSUMS[I]}" >&2
            echo "actual:   ${CHECKSUM}" >&2
            return 1
        fi
    done

    # extract
    mkdir -p "${SOURCE_DIR}"
    if [[ ! -d "${SOURCE_DIR}" ]]; then
        echo "unable to create directory: ${SOURCE_DIR}" >&2
        return 1
    fi
    for I in "${!PKGS[@]}"; do
        echo ""
        printf "Extracting  [%02i/%02i] %s " "$((I+1))" "${#PKGS[@]}" "${PKGS[I]}"
        if [[ -e "${SOURCE_DIR}/${NAMES[I]}" ]]; then
            rm -rf "${SOURCE_DIR}/${NAMES[I]}"
        fi
        mkdir -p "${SOURCE_DIR}/${NAMES[I]}"
        if ! tar -xf "${PKG_DIR}/${PKGS[I]}" -C "${SOURCE_DIR}/${NAMES[I]}" >/dev/null 2>&1; then
            if ! unzip -d "${SOURCE_DIR}/${NAMES[I]}" "${PKG_DIR}/${PKGS[I]}" >/dev/null 2>&1; then
                echo "unable to extract package: ${PKG_DIR}/${PKGS[I]}" >&2
                return 1
            fi
        fi
    done

    # create build and prefix directories
    mkdir -p "${BUILD_DIR}"
    mkdir -p "${BUILD_DIR_FOR_WIN}"
    if [[ ! -d "${BUILD_DIR}" ]]; then
        echo "unable to create directory: ${BUILD_DIR}" >&2
        return 1
    fi
    if [[ ! -d "${BUILD_DIR_FOR_WIN}" ]]; then
        echo "unable to create directory: ${BUILD_DIR_FOR_WIN}" >&2
        return 1
    fi

    mkdir -p "${MINGW_W64_DIR}"
    mkdir -p "${MINGW_W64_DIR_FOR_WIN}"
    if [[ ! -d "${MINGW_W64_DIR_FOR_WIN}" ]]; then
        echo "unable to create directory: ${MINGW_W64_DIR_FOR_WIN}" >&2
        return 1
    fi
    # 在linux系统中构建交叉编译器mingw-w64 for linux 参考<How to build a Mingw-w64 x86_64-w64-mingw32 cross-compiler> https://sourceforge.net/p/mingw-w64/wiki2/Cross%20Win32%20and%20Win64%20compiler/

    echo -e "\n"
    echo "Creating a cross Win32 and Win64 compiler"
    # build 
    local SYS_TYPE TOTAL
    SYS_TYPE=$("${SOURCE_DIR}/config/config-${CONFIG_VER}/config.guess")  #linux系统SYS_TYPE=86_64-pc-linux-gnu
    TOTAL=11
    if [[ "${DISABLE_GDB}" == true ]]; then
        TOTAL="$((${TOTAL} - 1))"
    fi

    # binutils
    echo ""
    printf "Building    [%02i/%02i] %s " "1" "${TOTAL}" "binutils ${BINUTILS_VER}"
    touch "${LOG_DIR}/binutils.log"
    mkdir -pv "${BUILD_DIR}/binutils" > "${LOG_DIR}/binutils.log" 2>&1 || return 1
    cd "${BUILD_DIR}/binutils"
    "${SOURCE_DIR}/binutils/binutils-${BINUTILS_VER}/configure" CC=gcc CXX=g++ --build="${SYS_TYPE}" --target="${TARGET}" --with-sysroot="${MINGW_W64_DIR}" --prefix="${MINGW_W64_DIR}" --enable-multilib --enable-targets=x86_64-w64-mingw32,i686-w64-mingw32 --disable-nls --disable-werror --enable-lto --disable-shared --enable-static >> "${LOG_DIR}/binutils.log" 2>&1 || return 1
    make -j "${JOBS}" MAKEINFO=true >> "${LOG_DIR}/binutils.log" 2>&1 || return 1
    make install-strip MAKEINFO=true >> "${LOG_DIR}/binutils.log" 2>&1 || return 1

    # update PATH  # 导入系统路径,必须在此处，否则mingw-w64 runtime报错
    export PATH="${MINGW_W64_DIR}/bin:${PATH}"

    # mingw-w64 headers
    echo ""
    printf "Building    [%02i/%02i] %s " "2" "${TOTAL}" "mingw-w64 ${MINGW_W64_VER} headers"
    touch "${LOG_DIR}/mingw-w64-headers.log"
    mkdir -pv "${BUILD_DIR}/mingw-w64-headers" > "${LOG_DIR}/mingw-w64-headers.log" 2>&1 || return 1
    cd "${BUILD_DIR}/mingw-w64-headers"
    "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-headers/configure" --build="${SYS_TYPE}" --host="${TARGET}" --prefix="${MINGW_W64_DIR}/${TARGET}" >> "${LOG_DIR}/mingw-w64-headers.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR}/mingw-w64-headers.log" 2>&1 || return 1

    # create symlinks
    touch "${LOG_DIR}/create-symlinks.log"
    cd "${MINGW_W64_DIR}"
    ln -s "${MINGW_W64_DIR}/${TARGET}" "${MINGW_W64_DIR}/mingw"
    #mkdir -pv "${MINGW_W64_DIR}/${TARGET}/lib" > "${LOG_DIR}/create-symlinks.log" 2>&1 || return 1
    ln -s "${MINGW_W64_DIR}/${TARGET}/lib" "${MINGW_W64_DIR}/${TARGET}/lib64 " > "${LOG_DIR}/create-symlinks.log" 2>&1 || return 1
    if [[ ! -d "usr" ]]; then
        ln -s . usr > "${LOG_DIR}/create-symlinks.log" 2>&1 || return 1
    fi
    if [[ ! -d "${TARGET}/include" ]]; then
        cd "${TARGET}"
        ln -s include ../include > "${LOG_DIR}/create-symlinks.log" 2>&1 || return 1
        cd "${MINGW_W64_DIR}"
    fi
    if [[ ! -d "${TARGET}/usr" ]]; then
        cd "${TARGET}"
        ln -s . usr > "${LOG_DIR}/create-symlinks.log" 2>&1 || return 1
        cd "${MINGW_W64_DIR}"
    fi
	
    # 构建gmp 或创建链接 ln -s "${SOURCE_DIR}/gmp/gmp-${GMP_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/gmp"
    #ln -s "${SOURCE_DIR}/gmp/gmp-${GMP_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/gmp"
    echo ""
    printf "Building    [%02i/%02i] %s " "3" "${TOTAL}" "gmp ${GMP_VER}"
    touch "${LOG_DIR}/gmp.log"
    local GMP_DIR
    GMP_DIR="${BUILD_DIR}/gmp-${GMP_VER}-${SYS_ARCH}"
    mkdir -pv "${BUILD_DIR}/gmp" > "${LOG_DIR}/gmp.log" 2>&1 || return 1
    cd "${BUILD_DIR}/gmp"
    "${SOURCE_DIR}/gmp/gmp-${GMP_VER}/configure" CC=gcc CXX=g++ CPPFLAGS=-fexceptions --build="${SYS_TYPE}" --prefix="${GMP_DIR}" --enable-cxx --disable-shared --enable-static >> "${LOG_DIR}/gmp.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR}/gmp.log" 2>&1 || return 1
    make check >> "${LOG_DIR}/gmp.log" 2>&1 || return 1
    make install >> "${LOG_DIR}/gmp.log" 2>&1 || return 1

    # 构建mpfr 或创建链接 ln -s "${SOURCE_DIR}/mpfr/mpfr-${MPFR_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/mpfr"
    #ln -s "${SOURCE_DIR}/mpfr/mpfr-${MPFR_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/mpfr"
    echo ""
    printf "Building    [%02i/%02i] %s " "4" "${TOTAL}" "mpfr ${MPFR_VER}"
    touch "${LOG_DIR}/mpfr.log"
    local MPFR_DIR
    MPFR_DIR="${BUILD_DIR}/mpfr-${MPFR_VER}-${SYS_ARCH}"
    mkdir -pv "${BUILD_DIR}/mpfr" > "${LOG_DIR}/mpfr.log" 2>&1 || return 1
    cd "${BUILD_DIR}/mpfr"
    "${SOURCE_DIR}/mpfr/mpfr-${MPFR_VER}/configure" CC=gcc CXX=g++ CFLAGS="-I${GMP_DIR}/include" CPPFLAGS="-I${GMP_DIR}/include" LDFLAGS="-L${GMP_DIR}/lib" --build="${SYS_TYPE}" --prefix="${MPFR_DIR}" --with-gmp="${GMP_DIR}" --disable-shared --enable-static >> "${LOG_DIR}/mpfr.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR}/mpfr.log" 2>&1 || return 1
    make install >> "${LOG_DIR}/mpfr.log" 2>&1 || return 1

    # 构建mpc 或创建链接 ln -s "${SOURCE_DIR}/mpc/mpc-${MPC_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/mpc"
    #ln -s "${SOURCE_DIR}/mpc/mpc-${MPC_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/mpc"
    echo ""
    printf "Building    [%02i/%02i] %s " "5" "${TOTAL}" "mpc ${MPC_VER}"
    touch "${LOG_DIR}/mpc.log"
    local MPC_DIR
    MPC_DIR="${BUILD_DIR}/mpc-${MPC_VER}-${SYS_ARCH}"
    mkdir -pv "${BUILD_DIR}/mpc" > "${LOG_DIR}/mpc.log" 2>&1 || return 1
    cd "${BUILD_DIR}/mpc"
    "${SOURCE_DIR}/mpc/mpc-${MPC_VER}/configure" CC=gcc CXX=g++ CFLAGS="-I${GMP_DIR}/include -I${MPFR_DIR}/include" CPPFLAGS="-I${GMP_DIR}/include -I${MPFR_DIR}/include" LDFLAGS="-L${GMP_DIR}/lib -L${MPFR_DIR}/lib" --build="${SYS_TYPE}" --prefix="${MPC_DIR}" --with-gmp="${GMP_DIR}" --with-mpfr="${MPFR_DIR}" --disable-shared --enable-static >> "${LOG_DIR}/mpc.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR}/mpc.log" 2>&1 || return 1
    make install >> "${LOG_DIR}/mpc.log" 2>&1 || return 1

    # 构建isl 或创建链接 ln -s "${SOURCE_DIR}/isl/isl-${ISL_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/isl"
    #ln -s "${SOURCE_DIR}/isl/isl-${ISL_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/isl"
    echo ""
    printf "Building    [%02i/%02i] %s " "6" "${TOTAL}" "isl ${ISL_VER}"
    touch "${LOG_DIR}/isl.log"
    local ISL_DIR
    ISL_DIR="${BUILD_DIR}/isl-${ISL_VER}-${SYS_ARCH}"
    mkdir -pv "${BUILD_DIR}/isl" > "${LOG_DIR}/isl.log" 2>&1 || return 1
    cd "${BUILD_DIR}/isl"
    "${SOURCE_DIR}/isl/isl-${ISL_VER}/configure" CC=gcc CXX=g++ CFLAGS="-I${GMP_DIR}/include" CPPFLAGS="-I${GMP_DIR}/include" LDFLAGS="-L${GMP_DIR}/lib" --build="${SYS_TYPE}" --prefix="${ISL_DIR}" --with-gmp="${GMP_DIR}" --disable-shared --enable-static >> "${LOG_DIR}/isl.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR}/isl.log" 2>&1 || return 1
    make install >> "${LOG_DIR}/isl.log" 2>&1 || return 1

    # gcc compilers
    echo ""
    printf "Building    [%02i/%02i] %s " "7" "${TOTAL}" "gcc ${GCC_VER} compilers"
    touch "${LOG_DIR}/gcc.log"
    local GCC_CONFIG_EXTRA
    GCC_CONFIG_EXTRA=()
    if [[ "${SYS_NAME}" == "darwin" ]]; then
        GCC_CONFIG_EXTRA+=("--with-system-zlib")
    fi
    mkdir -pv "${BUILD_DIR}/gcc" > "${LOG_DIR}/gcc.log" 2>&1 || return 1
    cd "${BUILD_DIR}/gcc"
    "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/configure" CFLAGS="-I${GMP_DIR}/include -I${MPFR_DIR}/include -I${MPC_DIR}/include -I${ISL_DIR}/include" CPPFLAGS="-I${GMP_DIR}/include -I${MPFR_DIR}/include -I${MPC_DIR}/include -I${ISL_DIR}/include" LDFLAGS="-L${GMP_DIR}/lib -L${MPFR_DIR}/lib -L${MPC_DIR}/lib -L${ISL_DIR}/lib" --build="${SYS_TYPE}" --host="${SYS_TYPE}" --target="${TARGET}" --prefix="${MINGW_W64_DIR}" --with-sysroot="${MINGW_W64_DIR}" --with-gmp="${GMP_DIR}" --with-mpfr="${MPFR_DIR}" --with-mpc="${MPC_DIR}" --with-isl="${ISL_DIR}" --enable-multilib --enable-targets=all --disable-nls --disable-libstdcxx-pch --disable-win32-registry --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran --enable-lto --disable-shared --enable-static "${GCC_CONFIG_EXTRA[@]}" >> "${LOG_DIR}/gcc.log" 2>&1 || return 1
    make -j "${JOBS}" all-gcc >> "${LOG_DIR}/gcc.log" 2>&1 || return 1
    make install-strip-gcc >> "${LOG_DIR}/gcc.log" 2>&1 || return 1

    # mingw-w64 runtime
    echo ""
    printf "Building    [%02i/%02i] %s " "8" "${TOTAL}" "mingw-w64 ${MINGW_W64_VER} runtime"
    touch "${LOG_DIR}/mingw-w64-crt.log"
    #export CC=""
    #export CXX=""
    local MINGW_W64_CONFIG_EXTRA
    MINGW_W64_CONFIG_EXTRA=()
    #if [[ "${TARGET}" == "${TARGET_i686}" ]]; then
    #    MINGW_W64_CONFIG_EXTRA+=("--enable-lib32" "--disable-lib64")
    #elif [[ "${TARGET}" == "${TARGET_x86_64}" ]]; then
    #    MINGW_W64_CONFIG_EXTRA+=("--enable-lib64" "--disable-lib32")
    #fi
    MINGW_W64_CONFIG_EXTRA+=("--enable-lib64" "--enable-lib32")
    mkdir -pv "${BUILD_DIR}/mingw-w64-crt" > "${LOG_DIR}/mingw-w64-crt.log" 2>&1 || return 1
    cd "${BUILD_DIR}/mingw-w64-crt"
    "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-crt/configure" --build="${SYS_TYPE}" --host="${TARGET}" --prefix="${MINGW_W64_DIR}/${TARGET}" --with-sysroot="${MINGW_W64_DIR}/${TARGET}" "${MINGW_W64_CONFIG_EXTRA[@]}" >> "${LOG_DIR}/mingw-w64-crt.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR}/mingw-w64-crt.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR}/mingw-w64-crt.log" 2>&1 || return 1

    # gcc libraries
    echo ""
    printf "Building    [%02i/%02i] %s " "9" "${TOTAL}" "gcc ${GCC_VER} libraries"
    touch "${LOG_DIR}/gcc.log"
    cd "${BUILD_DIR}/gcc"
    make -j "${JOBS}" all-target-libgcc >> "${LOG_DIR}/gcc.log" 2>&1 || return 1
    make -j "${JOBS}" install-target-libgcc >> "${LOG_DIR}/gcc.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR}/gcc.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR}/gcc.log" 2>&1 || return 1

    # winpthreads
    echo ""
    printf "Building    [%02i/%02i] %s " "10" "${TOTAL}" "winpthreads"
    touch "${LOG_DIR}/winpthreads.log"
    mkdir -pv "${BUILD_DIR}/winpthreads" > "${LOG_DIR}/winpthreads.log" 2>&1 || return 1
    cd "${BUILD_DIR}/winpthreads"
    "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-libraries/winpthreads/configure" --build="${SYS_TYPE}" --host="${TARGET}" --prefix="${MINGW_W64_DIR}" --disable-shared --enable-static >> "${LOG_DIR}/winpthreads.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR}/winpthreads.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR}/winpthreads.log" 2>&1 || return 1

    # gdb
    if [[ "${DISABLE_GDB}" == false ]]; then
        echo ""
        printf "Building    [%02i/%02i] %s " "11" "${TOTAL}" "gdb"
        touch "${LOG_DIR}/gdb.log"
        mkdir -pv "${BUILD_DIR}/gdb" > "${LOG_DIR}/gdb.log" 2>&1 || return 1
        cd "${BUILD_DIR}/gdb"
        # https://sourceware.org/bugzilla/show_bug.cgi?id=18113
        echo '#!/bin/sh' > makeinfo
        echo 'echo "makeinfo (GNU texinfo) 5.2"' >> makeinfo
        chmod a+x makeinfo
        "${SOURCE_DIR}/gdb/gdb-${GDB_VER}/configure" --build="${SYS_TYPE}" --host="${TARGET}" --prefix="${MINGW_W64_DIR}" -enable-multilib --enable-checking=release --enable-languages=c,c++ --enable-lto --disable-shared --enable-static MAKEINFO="${BUILD_DIR}/gdb/makeinfo" >> "${LOG_DIR}/gdb.log" 2>&1 || return 1
        make -j "${JOBS}" >> "${LOG_DIR}/gdb.log" 2>&1 || return 1
        make install >> "${LOG_DIR}/gdb.log" 2>&1 || return 1
        "${TARGET}"-strip "${MINGW_W64_DIR}/bin/gdb.exe" >> "${LOG_DIR}/gdb.log" 2>&1 || return 1
        "${TARGET}"-strip "${MINGW_W64_DIR}/bin/gdbserver.exe" >> "${LOG_DIR}/gdb.log" 2>&1 || return 1
    fi

    # clean up
    cd "${MINGW_W64_DIR}"
    find . -name "*.la" -type f -exec rm {} ";" >/dev/null 2>&1

    # done
    echo -e "\n"
    echo "  run the following command and add it to your shell startup script"
    echo "  (e.g., .bashrc or .bash_profile) to make persistent across sessions:"
    echo "    export PATH=\"${MINGW_W64_DIR}/bin:\${PATH}\""
    echo "    Cross compiler build complete."

  # 构建mingw-w64 for windows	参考https://sourceforge.net/p/mingw-w64/wiki2/Native Win64 compiler/
    echo -e "\n"
    echo "Creating a native Win64 compiler"
    echo ""
    # update PATH  # 导入系统路径 ，前面已经导入，此处不重复
    #export PATH="${MINGW_W64_DIR}/bin:${PATH}"
    #echo ""
    #echo "Make sure the cross compiler can be found"
    #echo ""
    #echo $PATH

    local SYS_TYPE TOTAL_FOR_WIN MAKE_INDEX NASM_INDEX WINPTHREADS_INDEX WINSTORECOMPAT_INDEX EXPAT_INDEX GDB_INDEX
    TOTAL_FOR_WIN=18
    WINSTORECOMPAT_INDEX=13
    WINPTHREADS_INDEX=14
    EXPAT_INDEX=15
    GDB_INDEX=16
    MAKE_INDEX=17
    NASM_INDEX=18
    if [[ "${DISABLE_GDB}" == true ]]; then
	MAKE_INDEX="$((${MAKE_INDEX} - 2))"
	NASM_INDEX="$((${NASM_INDEX} - 2))"
	TOTAL_FOR_WIN="$((${TOTAL_FOR_WIN} - 2))"
    fi

    # 构建binutils for windows
    echo ""
    printf "Building    [%02i/%02i] %s " "1" "${TOTAL_FOR_WIN}" "binutils ${BINUTILS_VER} for windows"
    touch "${LOG_DIR_FOR_WIN}/binutils.log"
    rm -f "${BUILD_DIR_FOR_WIN}/binutils"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/binutils" > "${LOG_DIR_FOR_WIN}/binutils.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/binutils"
    "${SOURCE_DIR}/binutils/binutils-${BINUTILS_VER}/configure" CC="${TARGET}-gcc" CXX="${TARGET}-g++" --host="${TARGET}" --target="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" --with-sysroot="${MINGW_W64_DIR_FOR_WIN}" --enable-multilib --enable-targets=x86_64-w64-mingw32,i686-w64-mingw32 --disable-nls --disable-werror --enable-lto --disable-shared --enable-static >> "${LOG_DIR}/binutils.log" 2>&1 || return 1
    make -j "${JOBS}" MAKEINFO=true >> "${LOG_DIR_FOR_WIN}/binutils.log" 2>&1 || return 1
    make install-strip MAKEINFO=true >> "${LOG_DIR_FOR_WIN}/binutils.log" 2>&1 || return 1

    # 运行构建程序前Make a 'winsup' directory
    echo ""
    printf "Copying     [%02i/%02i] %s " "2" "${TOTAL_FOR_WIN}" "copy the include directory to gcc-${GCC_VER}/gcc/winsup/mingw/"
    touch "${LOG_DIR_FOR_WIN}/winsup_mingw.log"
    cd "${SOURCE_DIR}/gcc/gcc-${GCC_VER}"
    rm -rf "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/winsup"
    mkdir -pv "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/winsup" > "${LOG_DIR_FOR_WIN}/winsup_mingw.log" 2>&1 || return 1
    mkdir -pv "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/winsup/mingw/" > "${LOG_DIR_FOR_WIN}/winsup_mingw.log" 2>&1 || return 1
    cd "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/winsup/mingw/"
    #cp -r "${MINGW_W64_DIR}/${TARGET}/include" "include"此处建议不采用复制方式，采用软链接
    ln -s "${MINGW_W64_DIR}/${TARGET}/include" "include"

    # 构建mingw-w64-headers for windows  --build=x86_64-w64-mingw32而不是--build="${SYS_TYPE}"
    echo ""
    printf "Building    [%02i/%02i] %s " "3" "${TOTAL_FOR_WIN}" "mingw-w64 ${MINGW_W64_VER} headers for windows"
    touch "${LOG_DIR_FOR_WIN}/mingw-w64-headers.log"
    rm -f "${BUILD_DIR_FOR_WIN}/mingw-w64-headers"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/mingw-w64-headers" > "${LOG_DIR_FOR_WIN}/mingw-w64-headers.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/mingw-w64-headers"
    "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-headers/configure" --host="${TARGET}" --build="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}/${TARGET}" >> "${LOG_DIR}/mingw-w64-headers.log" 2>&1 || return 1
    make -j "${JOBS}" MAKEINFO=true >> "${LOG_DIR_FOR_WIN}/mingw-w64-headers.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR_FOR_WIN}/mingw-w64-headers.log" 2>&1 || return 1
    # 创建symlink或者复制，此处复制
    # copies the directories
    cd "${MINGW_W64_DIR_FOR_WIN}"
    cp -r "${MINGW_W64_DIR_FOR_WIN}/${TARGET}/lib/"* "${MINGW_W64_DIR_FOR_WIN}/${TARGET}/lib64"	
    cp -r "${MINGW_W64_DIR_FOR_WIN}/${TARGET}" "${MINGW_W64_DIR_FOR_WIN}/mingw"

    # 创建链接 ln -s "${SOURCE_DIR}/gmp/gmp-${GMP_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/gmp"

    echo ""
    printf "Creating    [%02i/%02i] %s " "4" "${TOTAL_FOR_WIN}" "a symlink to gmp ${GMP_VER} for gcc"
    ln -s "${SOURCE_DIR}/gmp/gmp-${GMP_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/gmp"

    # 创建链接 ln -s "${SOURCE_DIR}/mpfr/mpfr-${MPFR_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/mpfr"

    echo ""
    printf "Creating    [%02i/%02i] %s " "5" "${TOTAL_FOR_WIN}" "a symlink to mpfr ${MPFR_VER} for gcc"
    ln -s "${SOURCE_DIR}/mpfr/mpfr-${MPFR_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/mpfr"

    # 创建链接 ln -s "${SOURCE_DIR}/mpc/mpc-${MPC_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/mpc"

    echo ""
    printf "Creating    [%02i/%02i] %s " "6" "${TOTAL_FOR_WIN}" "a symlink to mpc ${ISL_VER} for gcc"
    ln -s "${SOURCE_DIR}/mpc/mpc-${MPC_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/mpc"

    # 创建链接 ln -s "${SOURCE_DIR}/isl/isl-${ISL_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/isl"

    echo ""
    printf "Creating    [%02i/%02i] %s " "7" "${TOTAL_FOR_WIN}" "a symlink to isl ${ISL_VER} for gcc"
    ln -s "${SOURCE_DIR}/isl/isl-${ISL_VER}" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/isl"

    # gcc compilers
    echo ""
    printf "Building    [%02i/%02i] %s " "8" "${TOTAL_FOR_WIN}" "gcc ${GCC_VER} compilers for windows"
    touch "${LOG_DIR_FOR_WIN}/gcc.log"
    local GCC_CONFIG_EXTRA_FOR_WIN
    GCC_CONFIG_EXTRA_FOR_WIN=()
    if [[ "${SYS_NAME}" == "darwin" ]]; then
        GCC_CONFIG_EXTRA_FOR_WIN+=("--with-system-zlib")
    fi
    rm -f "${BUILD_DIR_FOR_WIN}/gcc"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/gcc" > "${LOG_DIR_FOR_WIN}/gcc.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/gcc"
    "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/configure" CFLAGS="-I/${MINGW_W64_DIR}/include" LDFLAGS="-L/${MINGW_W64_DIR}/lib" --host="${TARGET}" --target="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" --with-sysroot="${MINGW_W64_DIR_FOR_WIN}" --enable-targets=x86_64-w64-mingw32,i686-w64-mingw32 --enable-multilib --enable-fully-dynamic-string --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran --enable-lto --disable-shared --enable-static --enable-threads="win32" "${GCC_CONFIG_EXTRA_FOR_WIN[@]}" >> "${LOG_DIR_FOR_WIN}/gcc.log" 2>&1 || return 1 #--enable-threads=posix 所有平台支持的线程posix
    make -j "${JOBS}" all-gcc >> "${LOG_DIR_FOR_WIN}/gcc.log" 2>&1 || return 1
    make install-strip-gcc >> "${LOG_DIR_FOR_WIN}/gcc.log" 2>&1 || return 1

    # mingw-w64 runtime
    echo ""
    printf "Building    [%02i/%02i] %s " "9" "${TOTAL_FOR_WIN}" "mingw-w64 ${MINGW_W64_VER} runtime for windows"
    touch "${LOG_DIR_FOR_WIN}/mingw-w64-crt.log"
    export CC=""
    export CXX=""
    local MINGW_W64_CONFIG_EXTRA_FOR_WIN
    MINGW_W64_CONFIG_EXTRA_FOR_WIN=()
    #if [[ "${TARGET}" == "${TARGET_i686}" ]]; then
    #    MINGW_W64_CONFIG_EXTRA_FOR_WIN+=("--enable-lib32" "--disable-lib64")
    #elif [[ "${TARGET}" == "${TARGET_x86_64}" ]]; then
    #    MINGW_W64_CONFIG_EXTRA_FOR_WIN+=("--enable-lib64" "--disable-lib32")
    #fi
    MINGW_W64_CONFIG_EXTRA_FOR_WIN+=("--enable-lib64" "--enable-lib32")
    rm -f "${BUILD_DIR_FOR_WIN}/mingw-w64-crt"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/mingw-w64-crt" > "${LOG_DIR_FOR_WIN}/mingw-w64-crt.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/mingw-w64-crt"
    "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-crt/configure" CFLAGS="-I/${MINGW_W64_DIR}/include -L/${MINGW_W64_DIR}/lib" --host="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}/${TARGET}" --with-sysroot="${MINGW_W64_DIR_FOR_WIN}/${TARGET}" "${MINGW_W64_CONFIG_EXTRA_FOR_WIN[@]}" >> "${LOG_DIR_FOR_WIN}/mingw-w64-crt.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/mingw-w64-crt.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR_FOR_WIN}/mingw-w64-crt.log" 2>&1 || return 1

    # gcc libraries
    echo ""
    printf "Building    [%02i/%02i] %s " "10" "${TOTAL_FOR_WIN}" "gcc ${GCC_VER} libraries"
    touch "${LOG_DIR_FOR_WIN}/gcc.log"
    cd "${BUILD_DIR_FOR_WIN}/gcc"
    make -j "${JOBS}" all-target-libgcc >> "${LOG_DIR_FOR_WIN}/gcc.log" 2>&1 || return 1
    make -j "${JOBS}" install-target-libgcc >> "${LOG_DIR_FOR_WIN}/gcc.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/gcc.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR_FOR_WIN}/gcc.log" 2>&1 || return 1

    # relocate and symlink libs
    cd "${MINGW_W64_DIR_FOR_WIN}"
    cp -nr "${MINGW_W64_DIR_FOR_WIN}/${TARGET}/lib/"* "${MINGW_W64_DIR_FOR_WIN}/${TARGET}/lib64/"	
    cp -nr "${MINGW_W64_DIR_FOR_WIN}/${TARGET}/"* "${MINGW_W64_DIR_FOR_WIN}/mingw/"

    # libmangle
    echo ""
    printf "Building    [%02i/%02i] %s " "11" "${TOTAL_FOR_WIN}" "libmangle for windows"
    touch "${LOG_DIR_FOR_WIN}/libmangle.log"
    rm -f "${BUILD_DIR_FOR_WIN}/libmangle"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/libmangle" > "${LOG_DIR_FOR_WIN}/libmangle.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/libmangle"
    "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-libraries/libmangle/configure" --host="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" --disable-shared --enable-static >> "${LOG_DIR_FOR_WIN}/libmangle.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/libmangle.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR_FOR_WIN}/libmangle.log" 2>&1 || return 1

    # pseh
    if [[ "${TARGET}" == "${TARGET_x86_64}" ]]; then
	echo -e "\n"
        printf "Skiping     [%02i/%02i] %s " "12" "${TOTAL_FOR_WIN}" "Pseh:Only x86 32-bit Win32 host variants are supported"
    else
        echo ""
	printf "Building    [%02i/%02i] %s " "12" "${TOTAL_FOR_WIN}" "pseh for windows"
	touch "${LOG_DIR_FOR_WIN}/pseh.log"
	rm -f "${BUILD_DIR_FOR_WIN}/pseh"
	mkdir -pv "${BUILD_DIR_FOR_WIN}/pseh" > "${LOG_DIR_FOR_WIN}/pseh.log" 2>&1 || return 1
	cd "${BUILD_DIR_FOR_WIN}/pseh"
	"${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-libraries/pseh/configure" --prefix="${MINGW_W64_DIR_FOR_WIN}" --disable-shared --enable-static >> "${LOG_DIR_FOR_WIN}/pseh.log" 2>&1 || return 1
	make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/pseh.log" 2>&1 || return 1
	make install-strip >> "${LOG_DIR_FOR_WIN}/pseh.log" 2>&1 || return 1
    fi

    # winstorecompat
    echo ""
    printf "Building    [%02i/%02i] %s " "${WINSTORECOMPAT_INDEX}" "${TOTAL_FOR_WIN}" "winstorecompat for windows"
    touch "${LOG_DIR_FOR_WIN}/winstorecompat.log"
    rm -f "${BUILD_DIR_FOR_WIN}/winstorecompat"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/winstorecompat" > "${LOG_DIR_FOR_WIN}/winstorecompat.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/winstorecompat"
    "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-libraries/winstorecompat/configure" --host="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" --disable-shared --enable-static >> "${LOG_DIR_FOR_WIN}/winstorecompat.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/winstorecompat.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR_FOR_WIN}/winstorecompat.log" 2>&1 || return 1

    # winpthreads
    echo ""
    printf "Building    [%02i/%02i] %s " "${WINPTHREADS_INDEX}" "${TOTAL_FOR_WIN}" "winpthreads for windows"
    touch "${LOG_DIR_FOR_WIN}/winpthreads.log"
    rm -f "${BUILD_DIR_FOR_WIN}/winpthreads"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/winpthreads" > "${LOG_DIR_FOR_WIN}/winpthreads.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/winpthreads"
    "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-libraries/winpthreads/configure" --host="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" --disable-shared --enable-static >> "${LOG_DIR_FOR_WIN}/winpthreads.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/winpthreads.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR_FOR_WIN}/winpthreads.log" 2>&1 || return 1
    
    # expat and gdb
    if [[ "${DISABLE_GDB}" == false ]]; then
    # expat
    echo ""
    printf "Building    [%02i/%02i] %s " "15" "${TOTAL_FOR_WIN}" "expat for windows"
    touch "${LOG_DIR_FOR_WIN}/expat.log"
    rm -f "${BUILD_DIR_FOR_WIN}/expat"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/expat" > "${LOG_DIR_FOR_WIN}/expat.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/expat"
    "${SOURCE_DIR}/expat/expat-${EXPAT_VER}/configure" --host="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" >> "${LOG_DIR_FOR_WIN}/expat.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/expat.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR_FOR_WIN}/expat.log" 2>&1 || return 1
    # gdb
        echo ""
        printf "Building    [%02i/%02i] %s " "16" "${TOTAL_FOR_WIN}" "gdb for windows"
        touch "${LOG_DIR_FOR_WIN}/gdb.log"
        rm -f "${BUILD_DIR_FOR_WIN}/gdb"
        mkdir -pv "${BUILD_DIR_FOR_WIN}/gdb" > "${LOG_DIR_FOR_WIN}/gdb.log" 2>&1 || return 1
        cd "${BUILD_DIR_FOR_WIN}/gdb"
        # https://sourceware.org/bugzilla/show_bug.cgi?id=18113
        echo '#!/bin/sh' > makeinfo
        echo 'echo "makeinfo (GNU texinfo) 5.2"' >> makeinfo
        chmod a+x makeinfo
        "${SOURCE_DIR}/gdb/gdb-${GDB_VER}/configure" --host="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" -enable-multilib --enable-checking=release --enable-languages=c,c++,fortran --enable-lto --disable-shared --enable-static MAKEINFO="${BUILD_DIR_FOR_WIN}/gdb/makeinfo" >> "${LOG_DIR_FOR_WIN}/gdb.log" 2>&1 || return 1
        make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/gdb.log" 2>&1 || return 1
        make install >> "${LOG_DIR_FOR_WIN}/gdb.log" 2>&1 || return 1
        "${TARGET}"-strip "${MINGW_W64_DIR_FOR_WIN}/bin/gdb.exe" >> "${LOG_DIR_FOR_WIN}/gdb.log" 2>&1 || return 1
        "${TARGET}"-strip "${MINGW_W64_DIR_FOR_WIN}/bin/gdbserver.exe" >> "${LOG_DIR_FOR_WIN}/gdb.log" 2>&1 || return 1
    fi

    # make
    echo ""
    printf "Building    [%02i/%02i] %s " "${MAKE_INDEX}" "${TOTAL_FOR_WIN}" "make for windows"
    touch "${LOG_DIR_FOR_WIN}/make.log"
    rm -f "${BUILD_DIR_FOR_WIN}/make"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/make" > "${LOG_DIR_FOR_WIN}/make.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/make"
    "${SOURCE_DIR}/make/make-${MAKE_VER}/configure" --host="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" >> "${LOG_DIR_FOR_WIN}/make.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/make.log" 2>&1 || return 1
    make install-strip >> "${LOG_DIR_FOR_WIN}/make.log" 2>&1 || return 1

    #nasm
    echo ""
    printf "Building    [%02i/%02i] %s " "${NASM_INDEX}" "${TOTAL_FOR_WIN}" "nasm for windows"
    touch "${LOG_DIR_FOR_WIN}/nasm.log"
    rm -f "${BUILD_DIR_FOR_WIN}/nasm"
    mkdir -pv "${BUILD_DIR_FOR_WIN}/nasm" > "${LOG_DIR_FOR_WIN}/nasm.log" 2>&1 || return 1
    cd "${BUILD_DIR_FOR_WIN}/nasm"
    "${SOURCE_DIR}/nasm/nasm-${NASM_VER}/configure" --host="${TARGET}" --prefix="${MINGW_W64_DIR_FOR_WIN}" >> "${LOG_DIR_FOR_WIN}/nasm.log" 2>&1 || return 1
    make -j "${JOBS}" >> "${LOG_DIR_FOR_WIN}/nasm.log" 2>&1 || return 1
    make install>> "${LOG_DIR_FOR_WIN}/nasm.log" 2>&1 || return 1

    # clean up
    cd "${MINGW_W64_DIR_FOR_WIN}"
    find . -name "*.la" -type f -exec rm {} ";" >/dev/null 2>&1

    # done
    echo ""
    echo "Complete."
    return 0
    cd ../
    cd ../
    chmod -R 777 "$PWD"
    
    set +o pipefail
}

trap die_gracefully EXIT INT TERM

mingw-w64-build "${@}" &
PID=$!
display_progress "${PID}"
wait "${PID}" || CODE=$?

trap - EXIT INT TERM

if [[ "${CODE}" -ne 0 ]]; then
    PARAMS=()
    for PARAM in "${@}"; do
        if [[ "${PARAM#-}" != "${PARAM}" ]]; then
            continue
        fi
        PARAMS+=("${PARAM}")
    done
    TDIR="${PARAMS[1]}"
    echo ""
    echo "error: subprocess returned non-zero error code (${CODE})" >&2
    echo "logs and temporary files may exist at ${TDIR:-$HOME/toolchains}" >&2
    exit 1
fi
exit 0
